//
// Copyright (c) Hisilicon Corporation.  All rights reserved.
//
//
/*

Module Name:
    Ewldrv.cpp
Abstract:
    Encoder driver for Hantro hardware

Notes:
    

Revision History:
    2007-8-15    m55267   create
    
--*/

#include <windows.h>
#include <dbgapi.h>
#include "HiMemMap.h"
#include "hisi6810_gpio.h"
#include "HiIoMap.h"

/* First Stack */
#define HI_REG_BASE_1       0x20000000 /* From GE */
#define HI_REG_OFFSET_1     (0x8FFFF + 1)    /* To DMAC */

/* Second Stack */
#define HI_REG_BASE_2       0x30000000 /* From MMC1 */
#define HI_REG_OFFSET_2     (0x5FFFFF + 1)  /* TO ESI S2 */

#define TOTAL_REG_SPACE     (HI_REG_OFFSET_1 + HI_REG_OFFSET_2) /* Add 2 for Align */

#define DRV_RESERVED_SIZE   (DRV_BUF_SIZE) 

void* g_pRegVirtualAddr = NULL;
void* g_pResMemVirtualAddr = NULL;



PVOID MapIoSpace( 
  PHYSICAL_ADDRESS PhysicalAddress, 
  ULONG NumberOfBytes, 
  BOOLEAN CacheEnable 
)
{
    int iMemResv = 0;
    

    // Return the address base on PhysicalAddress
    if (PhysicalAddress.QuadPart >= HI_REG_BASE_1 
        && PhysicalAddress.QuadPart <= (HI_REG_BASE_1 + HI_REG_OFFSET_1))
    {
        // Size in the scope?
        if ((PhysicalAddress.QuadPart + NumberOfBytes) <= (HI_REG_BASE_1 + HI_REG_OFFSET_1))
        {
            //NKDbgPrintfW(TEXT("****%s 1: NumberOfBytes=%d return add=0x%x\r\n"), 
            //        TEXT(__FUNCTION__), NumberOfBytes, (DWORD)((BYTE*)g_pRegVirtualAddr + (PhysicalAddress.QuadPart - HI_REG_BASE_1)));        
            
            return ((BYTE*)g_pRegVirtualAddr + (PhysicalAddress.QuadPart - HI_REG_BASE_1));
        }
        // Not in the scope
        else
        {
            NKDbgPrintfW(TEXT("****%s 1: Bad Addr[0x%x] + size=%d\r\n"), 
                    TEXT(__FUNCTION__), (DWORD)PhysicalAddress.QuadPart, NumberOfBytes);        
            return NULL;
        }
    }
    else if (PhysicalAddress.QuadPart >= HI_REG_BASE_2 
        && PhysicalAddress.QuadPart <= (HI_REG_BASE_2 + HI_REG_OFFSET_2))
    {
        // Size in the scope?
        if ((PhysicalAddress.QuadPart + NumberOfBytes) <= (HI_REG_BASE_2 + HI_REG_OFFSET_2))
        {
            //NKDbgPrintfW(TEXT("****%s 2 NumberOfBytes=%d return add=0x%x\r\n"), 
            //        TEXT(__FUNCTION__), NumberOfBytes, (DWORD)((BYTE*)g_pRegVirtualAddr + HI_REG_OFFSET_1 + (PhysicalAddress.QuadPart - HI_REG_BASE_2)));        
        
            return ((BYTE*)g_pRegVirtualAddr + HI_REG_OFFSET_1 + (PhysicalAddress.QuadPart - HI_REG_BASE_2));
        }
        // Not in the scope
        else
        {
            NKDbgPrintfW(TEXT("****%s 2: Bad Addr[0x%x] + size=%d\r\n"), 
                    TEXT(__FUNCTION__), (DWORD)PhysicalAddress.QuadPart, NumberOfBytes);        
            return NULL;
        }
    }
    // Map Reservered Memory?
    else if (PhysicalAddress.QuadPart >= MEM_ADD_BASE 
        && (PhysicalAddress.QuadPart + NumberOfBytes) <= (MEM_ADD_BASE + DRV_RESERVED_SIZE))
    {
        //NKDbgPrintfW(TEXT("****%s 3 NumberOfBytes=%d return add=0x%x\r\n"), 
        //        TEXT(__FUNCTION__), NumberOfBytes, (DWORD)((BYTE*)g_pResMemVirtualAddr + (PhysicalAddress.QuadPart - MEM_ADD_BASE)));        
    
        return ((BYTE*)g_pResMemVirtualAddr + (PhysicalAddress.QuadPart - MEM_ADD_BASE));
    }
    else
    {
        NKDbgPrintfW(TEXT("****%s: Addr(0x%x) or size(%d) Not Reservered!!\r\n"), TEXT(__FUNCTION__), 
            (DWORD)PhysicalAddress.QuadPart, NumberOfBytes);      
            
        return NULL;//MmMapIoSpace(PhysicalAddress, NumberOfBytes, CacheEnable);
    }
}

bool UnMapIoSpace( 
  PVOID BaseAddress, 
  ULONG NumberOfBytes 
)
{
    if ((BaseAddress >= g_pRegVirtualAddr)
       && ((BYTE*)BaseAddress + NumberOfBytes) <= ((BYTE*)g_pRegVirtualAddr + TOTAL_REG_SPACE))
    {
    	return TRUE;
    }
    else if (BaseAddress >= g_pResMemVirtualAddr
       && ((BYTE*)BaseAddress + NumberOfBytes) <= ((BYTE*)g_pResMemVirtualAddr + DRV_RESERVED_SIZE))
    {
    	return TRUE;
    }
    else
    {
        NKDbgPrintfW(TEXT("****%s: Addr(0x%x vs [0x%x][0x%x]) or size(%d) Not Reservered!!\r\n"), TEXT(__FUNCTION__), 
            BaseAddress, g_pRegVirtualAddr, g_pResMemVirtualAddr, NumberOfBytes);      
            
        //MmUnmapIoSpace(BaseAddress, NumberOfBytes);
        return FALSE;
    }
}

BOOL GetReservedMemInfo( RES_MEM_MODULE_EN enType, RES_MEM_INFO* pMemInfo)
{
    if (NULL == pMemInfo || NULL == g_pResMemVirtualAddr)
    {
        NKDbgPrintfW(TEXT("****%s: NULL == pMemInfo || NULL == g_pResMemVirtualAddr!!\r\n"), TEXT(__FUNCTION__));      
        return FALSE;
    }
    
    DWORD dwOffset = 0;
    memset(pMemInfo, 0, sizeof(*pMemInfo));
    
    switch (enType)
    {
        case MODULE_CAMERA_ICU:
            pMemInfo->PhysicalAddress.QuadPart = HISI_ICU_CAMERA_DMA_PA;
            pMemInfo->NumberOfBytes            = HISI_ICU_CAMERA_DMA_SIZE;
            break;
            
        case MODULE_ENCODE:
            pMemInfo->PhysicalAddress.QuadPart = HISI_HANTRO_ENCODER_DMA_PA;
            pMemInfo->NumberOfBytes            = HISI_HANTRO_ENCODER_DMA_SIZE;
            break;
            
        case MODULE_DECODE:
            pMemInfo->PhysicalAddress.QuadPart = HISI_HANTRO_DECODER_DMA_PA;
            pMemInfo->NumberOfBytes            = HISI_HANTRO_DECODER_DMA_SIZE;
            break;
            
        case MODULE_FB_EDC:
            pMemInfo->PhysicalAddress.QuadPart = HISI_EDC_FRAME_BUFFER_PA;
            pMemInfo->NumberOfBytes            = HISI_EDC_FRAME_BUFFER_SIZE;
            break;
            
        default:
            NKDbgPrintfW(TEXT("****Error !!! %s: Bad enType=%d \r\n"), TEXT(__FUNCTION__), enType);      
            return FALSE;
    }

    pMemInfo->VirtualAddress = ((BYTE*)g_pResMemVirtualAddr) + (pMemInfo->PhysicalAddress.QuadPart - MEM_ADD_BASE);
    
    return TRUE;
}


EXTERN_C DWORD IOM_Init(VOID * pContext)
{    
    int iMemResv = 0;
    PHYSICAL_ADDRESS phyAddr;
    
    ASSERT(pContext);
    if (NULL == g_pRegVirtualAddr)
    {
        NKDbgPrintfW(TEXT("****%s: Begin VirtualAlloc BSP_RESERVE_SIZE=%d RESERVED_APP_SIZE=%d DRV_BUF_SIZE=%d MEM_BUF_END=%d HISI_EDC_FRAME_BUFFER_PA=0x%x\r\n"), TEXT(__FUNCTION__), 
            BSP_RESERVE_SIZE, RESERVED_APP_SIZE, DRV_BUF_SIZE, MEM_BUF_END, HISI_EDC_FRAME_BUFFER_PA);
        g_pRegVirtualAddr = VirtualAlloc(NULL, 
                TOTAL_REG_SPACE, MEM_RESERVE, PAGE_NOACCESS);
                
        if (NULL == g_pRegVirtualAddr)
        {
            NKDbgPrintfW(TEXT("****%s: VirtualAlloc Failed! size=%d\r\n"), TEXT(__FUNCTION__), TOTAL_REG_SPACE);
            return NULL;
        }
        
        if (!VirtualCopy((PVOID)g_pRegVirtualAddr, (LPVOID)(HI_REG_BASE_1 >> 8 ), 
            HI_REG_OFFSET_1, PAGE_READWRITE|PAGE_PHYSICAL|PAGE_NOCACHE))
        {
            NKDbgPrintfW(TEXT("****%s: VirtualCopy Failed! size=%d\r\n"), TEXT(__FUNCTION__), HI_REG_OFFSET_1);
            return NULL;
        }

        if (!VirtualCopy((PVOID)(((BYTE*)g_pRegVirtualAddr) + HI_REG_OFFSET_1), 
            (LPVOID)(HI_REG_BASE_2  >> 8), 
            HI_REG_OFFSET_2, PAGE_READWRITE|PAGE_PHYSICAL|PAGE_NOCACHE))
        {
            NKDbgPrintfW(TEXT("****%s: VirtualCopy Failed! size=%d\r\n"), 
                    TEXT(__FUNCTION__), HI_REG_OFFSET_2);
            return NULL;
        }               


        ///////////////////////////////////////////////////////////////
        //////////////// Map reserved memory
        iMemResv = DRV_RESERVED_SIZE;
        
        /* > 2M for upper end memory */
        if (iMemResv < 0x200100)
        {
            iMemResv = 0x200100;
            NKDbgPrintfW(TEXT("****%s: iMemResv from 0x%x Align to =0x%x\r\n"), 
                    TEXT(__FUNCTION__), DRV_RESERVED_SIZE, iMemResv);           
        }

        phyAddr.QuadPart = MEM_ADD_BASE;
        
        g_pResMemVirtualAddr = (PBYTE)MmMapIoSpace(
                                 phyAddr,
                                 iMemResv,
                                 FALSE);
        NKDbgPrintfW(TEXT("****%s: MmMapIoSpace: Reg Addr=0x%x Reserved Memory Addr=0x%x Success!!!\r\n"), 
                TEXT(__FUNCTION__), g_pRegVirtualAddr, g_pResMemVirtualAddr);
          
        /*if (!VirtualCopy((PVOID)(((BYTE*)g_pRegVirtualAddr) + HI_REG_OFFSET_1 + HI_REG_OFFSET_2), 
            (LPVOID)(MEM_ADD_BASE  >> 8), 
            DRV_RESERVED_SIZE, PAGE_READWRITE|PAGE_PHYSICAL|PAGE_NOCACHE))
        {
            NKDbgPrintfW(TEXT("****%s: VirtualCopy Failed! size=%d\r\n"), 
                    TEXT(__FUNCTION__), DRV_RESERVED_SIZE);
            return NULL;
        }               
        
        g_pResMemVirtualAddr = (BYTE*)(g_pRegVirtualAddr) + HI_REG_OFFSET_1 + HI_REG_OFFSET_2;
                           
        NKDbgPrintfW(TEXT("****%s: MmMapIoSpace: Reg Addr=0x%x Reserved Memory Addr=0x%x Success!!!\r\n"), 
                TEXT(__FUNCTION__), g_pRegVirtualAddr, g_pResMemVirtualAddr);*/
    }
    else
    {
        NKDbgPrintfW(TEXT("****Error: %s: g_pRegVirtualAddr!=NULL\r\n"), TEXT(__FUNCTION__));           
        SetLastError( ERROR_OUTOFMEMORY );
        return NULL;
    }
    

    return reinterpret_cast<DWORD>(g_pRegVirtualAddr);
}


EXTERN_C BOOL IOM_Deinit(DWORD dwContext)
{

    return TRUE;
}


EXTERN_C BOOL IOM_IOControl(
    DWORD   dwContext,
    DWORD   Ioctl,
    UCHAR * pInBufUnmapped,
    DWORD   InBufLen, 
    UCHAR * pOutBufUnmapped,
    DWORD   OutBufLen,
    DWORD * pdwBytesTransferred
   )
{
    UCHAR * pInBuf  = NULL;
    UCHAR * pOutBuf = NULL;
    /*UCHAR * pBytesTransferred;*/
    DWORD   dwErr = ERROR_SUCCESS;
    if ((NULL == g_pRegVirtualAddr) || (NULL == g_pResMemVirtualAddr))
    {
        NKDbgPrintfW(TEXT("****%s Error: g_pRegVirtualAddr=0x%x g_pResMemVirtualAddr=0x%x\r\n"), TEXT(__FUNCTION__), 
            g_pRegVirtualAddr, g_pResMemVirtualAddr);
        return FALSE;
    }
    
    pInBuf = (UCHAR*) MapCallerPtr(pInBufUnmapped, InBufLen );
    if (( pInBuf == NULL ) && ( pInBufUnmapped != NULL ))
    {
        NKDbgPrintfW( _T("EDR_IOControl(%08x):  MapCallerPtr failed for incoming buffer.\r\n"), dwContext  );

        return FALSE;
    }

    pOutBuf = (UCHAR*) MapCallerPtr(pOutBufUnmapped, OutBufLen );
    if (( NULL == pOutBuf ) && ( pOutBufUnmapped != NULL ))
    {
        NKDbgPrintfW(_T("EDR_IOControl(%08x): MapCallerPtr failed for outcoming buffer.\r\n"), dwContext );

        return FALSE;
    }

    /*pBytesTransferred = (UCHAR*)MapCallerPtr( pdwBytesTransferred, sizeof(DWORD));
    if ( NULL ==  pBytesTransferred && pdwBytesTransferred != NULL)
    {
        DEBUGMSG( ZONE_EWLDRIVER, ( _T("EDR_IOControl(%08x): MapCallerPtr failed for dwBytesTransferred.\r\n"), dwContext ) );
        return ERROR_INVALID_PARAMETER;
    }*/

    
    switch ( Ioctl )
    {
    case IOCTL_IOM_MAP:        
        {
            MAP_IO_STRU *pstMap = (MAP_IO_STRU*)pInBuf;
            
            *((PVOID*)pOutBuf) = MapIoSpace(pstMap->PhysicalAddress, 
                    pstMap->NumberOfBytes, pstMap->CacheEnable);
            if (NULL == pOutBuf)        
            {
            	dwErr = ERROR_INVALID_PARAMETER;
            }
        }
        break;
        
    case IOCTL_IOM_UNMAP:  
        {
            UNMAP_IO_STRU *pstMap = (UNMAP_IO_STRU*)pInBuf;
            
            return UnMapIoSpace(pstMap->BaseAddress, pstMap->NumberOfBytes);
        }
        break;

    case IOCTL_IOM_GET_RESERVED:  
        {
            RES_MEM_MODULE_EN enType = *(RES_MEM_MODULE_EN*)pInBuf;
            RES_MEM_INFO *pMemInfo = (RES_MEM_INFO*)pOutBuf;
            NKDbgPrintfW(TEXT("IOCTL_IOM_GET_RESERVED enType=%d\n"), enType);
            return GetReservedMemInfo( enType, pMemInfo);
        }
        break;
   
    default:
        NKDbgPrintfW(TEXT("IOM_IOControl(%08x): Unsupported IOCTL code %u\r\n"), dwContext, Ioctl );/*lint !e64 !e522*/           
        dwErr = ERROR_NOT_SUPPORTED;
        break;
    }
    
    // pass back appropriate response codes
    if (dwErr != ERROR_SUCCESS)
    {
        SetLastError(dwErr) ;
    }

    return ( ( dwErr == ERROR_SUCCESS ) ? TRUE : FALSE );
}


EXTERN_C DWORD IOM_Open(DWORD Context, DWORD Access, DWORD ShareMode)
{
    //NKDbgPrintfW(TEXT("****%s : 0x%x\r\n"), TEXT(__FUNCTION__), Context);
    return Context;
}


EXTERN_C BOOL IOM_Close( DWORD Context) 
{
    //NKDbgPrintfW(TEXT("****%s : 0x%x\r\n"), TEXT(__FUNCTION__), Context);    
    return TRUE;
}

BOOL
__stdcall
DllMain(
   HANDLE   hDllHandle, 
   DWORD    dwReason, 
   VOID   * lpReserved
   ) 
{/*lint !e18*/           
    BOOL bRc = TRUE;
    
    UNREFERENCED_PARAMETER( lpReserved );
    
    switch ( dwReason )
        {
        case DLL_PROCESS_ATTACH: 
            {
 
            break;
            } 

        case DLL_PROCESS_DETACH: 
            {
 
            break;
            } 
            
        case DLL_THREAD_DETACH:
            {
            break;
            }
            
        case DLL_THREAD_ATTACH:
            {
            break;
            }
            
        default:
            {
            break;
            }
        }
    
    return bRc;
}/*lint !e818 !e715*/           





